﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using ECode.ECommon.Extensions;
using ECode.EComPort.Base;
using ECode.ModbusTester.Lib.ViewModel;

namespace ECode.ModbusTester
{
    public partial class FrmMain : Form
    {
        private ESerialPort _com = new ESerialPort();
        private CounterViewModel _counter = new CounterViewModel();
        private ModbusCmdViewModel _modCmd = new ModbusCmdViewModel();
        private ReceiveViewModel _recView = new ReceiveViewModel();
        private SendViewModel _sendView = new SendViewModel();
        public SerialPortViewModel _comView = new SerialPortViewModel();
        private bool _canSend;
        private Thread _sendThread;
        private string _fileName;
        public FrmMain()
        {
            InitializeComponent();
        }

        private void FrmMain_Shown(object sender, EventArgs e)
        {
            //CheckForIllegalCrossThreadCalls = false;

            ComBinding();
            _comView.Com = _com;

            ModbusBinding();

            SendBinding();

            GbModbus.Visible = false;
            this.Width -= GbModbus.Width;

            GbRead.Enabled = GbWrite.Enabled = false;

            //ChkSendHex.CheckedChanged += OnHexShowCheckedChanged;
            //ChkRecHex.CheckedChanged += OnHexShowCheckedChanged;
            ChkAuto.CheckedChanged += OnHexShowCheckedChanged;
            ChkNewLine.CheckedChanged += OnHexShowCheckedChanged;
        }

        private void OnHexShowCheckedChanged(object sender, EventArgs eventArgs)
        {
            //_recView.IsHexShow = ChkRecHex.Checked;
            //_sendView.IsHexShow = ChkSendHex.Checked;
            _sendView.IsNewLine = ChkNewLine.Checked;
            _sendView.IsAuto = ChkAuto.Checked;
        }

        private void BtnOpen_Click(object sender, EventArgs e)
        {
            if (BtnOpen.Text.Contains("打开"))
            {
                _comView.Open();
                _sendView.Com = _com;
                _sendView.ComDataType = _comView.ComDataType;
                BtnOpen.Text = BtnOpen.Text.Replace("打开", "关闭");
            }
            else
            {
                _comView.Close();
                BtnOpen.Text = BtnOpen.Text.Replace("关闭", "打开");
            }
        }

        private void BtnClearCount_Click(object sender, EventArgs e)
        {
            _counter.Clear();
        }

        private void BtnModbus_Click(object sender, EventArgs e)
        {
            if (BtnModbus.Text.Contains("打开"))
            {
                GbModbus.Visible = true;
                this.Width += GbModbus.Width;
                BtnModbus.Text = BtnModbus.Text.Replace("打开", "关闭");
            }
            else
            {
                GbModbus.Visible = false;
                this.Width -= GbModbus.Width;
                BtnModbus.Text = BtnModbus.Text.Replace("关闭", "打开");
            }
        }

        private void BtnExit_Click(object sender, EventArgs e)
        {
            _comView.Close();
            Environment.Exit(0);
        }

        private void BtnSend_Click(object sender, EventArgs e)
        {
            _canSend = true;
            _sendView.SendData = TxtSend.Text;
            if (_sendThread != null && _sendThread.IsAlive) return;
            _sendThread = new Thread(SendThreadRun);
            _sendThread.IsBackground = true;
            _sendThread.Start();
        }
        private void BtnStop_Click(object sender, EventArgs e)
        {
            _canSend = false;
            _sendThread.Join();
            _sendThread.Abort();
        }
        private void BtnClearSend_Click(object sender, EventArgs e)
        {
            TxtSend.Clear();
            _sendView.Clear();
        }

        private void BtnRecClear_Click(object sender, EventArgs e)
        {
            TxtRec.Clear();
            _recView.Clear();
        }

        private void BtnSave_Click(object sender, EventArgs e)
        {
            if (Ofd.ShowDialog() != DialogResult.OK) return;
            _fileName = Ofd.FileName;
        }
        private void CbbOptType_SelectedIndexChanged(object sender, EventArgs e)
        {
            CbbFunCode.Items.Clear();
            _modCmd.OptType = CbbOptType.Text;
            if (_modCmd.OptType.Equals("读操作"))
            {
                GbWrite.Enabled = false;
                GbRead.Enabled = true;
            }
            else
            {
                GbRead.Enabled = false;
                GbWrite.Enabled = true;
            }
            CbbFunCode.Text = string.Empty;
            CbbFunCode.Items.AddRange(_modCmd.GetFunCode());
        }
        private void BtnMakeModbus_Click(object sender, EventArgs e)
        {
            _modCmd.Create();
            TxtSend.Text = _modCmd.Cmd;
        }
        private void TmrCom_Tick(object sender, EventArgs e)
        {
            TmrCom.Enabled = false;
            ComScan();
        }

        protected override void WndProc(ref Message msg)
        {
            switch (msg.Msg)
            {
                case 537://当设备的硬件配置改变时发送此消息给应用程序或设备驱动程序                    
                    TmrCom.Interval = 1000;
                    TmrCom.Enabled = true;
                    break;
                default:
                    base.WndProc(ref msg);
                    break;
            }
        }

        #region
        /// <summary>
        /// 串口扫描
        /// </summary>
        void ComScan()
        {
            var ns = _comView.ComNames;
            var s = string.Join(",", ns);

            var regex = new Regex("COM\\d+");
            CbbCom.Items.Clear();
            foreach (var n in s.Split(','))
            {
                var t = regex.Match(n);
                CbbCom.Items.Add(t);
            }
        }
        /// <summary>
        /// 绑定串口设置
        /// </summary>
        void ComBinding()
        {
            _comView.Com = _com;
            ComScan();

            CbbCom.DataBindings.Add(new Binding("Text", _comView, "ComName"));

            CbbBaud.Items.Clear();
            CbbBaud.Items.AddRange(_comView.BaudItems);
            CbbBaud.DataBindings.Add(new Binding("Text", _comView, "Baud"));
            _comView.Baud = CbbBaud.Text = CbbBaud.Items[6].ToString();

            CbbDataBit.Items.Clear();
            CbbDataBit.Items.AddRange(_comView.DataBitItems);
            CbbDataBit.DataBindings.Add(new Binding("Text", _comView, "DataBit"));
            _comView.DataBit = CbbDataBit.Text = CbbDataBit.Items[3].ToString();

            CbbStopBit.Items.Clear();
            CbbStopBit.Items.AddRange(_comView.StopBitItems);
            CbbStopBit.DataBindings.Add(new Binding("Text", _comView, "StopBit"));
            _comView.StopBit = CbbStopBit.Text = CbbStopBit.Items[1].ToString();

            CbbParity.Items.Clear();
            CbbParity.Items.AddRange(_comView.ParityItems);
            CbbParity.DataBindings.Add(new Binding("Text", _comView, "Parity"));
            _comView.Parity = CbbParity.Text = CbbParity.Items[0].ToString();

            CbbEncoding.Items.Clear();
            CbbEncoding.Items.AddRange(_comView.EncodingType);
            CbbEncoding.DataBindings.Add(new Binding("Text", _comView, "ComDataType"));
            _comView.ComDataType = CbbEncoding.Text = CbbEncoding.Items[0].ToString();

            LblComMsg.DataBindings.Add(new Binding("Text", _comView, "Msg"));

            _comView.OnRecevied += OnRecevied;
        }
        /// <summary>
        /// Modbus指令块绑定
        /// </summary>
        void ModbusBinding()
        {
            NumNo.DataBindings.Add(new Binding("Value", _modCmd, "InstrAddr"));
            NumAddr.DataBindings.Add(new Binding("Value", _modCmd, "Addr"));
            NumLen.DataBindings.Add(new Binding("Value", _modCmd, "GetLen"));
            TxtWrite.DataBindings.Add(new Binding("Text", _modCmd, "WriteValue"));

            //TxtSend.DataBindings.Add(new Binding("Text", _modCmd, "Cmd"));

            RbHex.CheckedChanged += new EventHandler(RadioButtonChecked);
            RbFloat.CheckedChanged += new EventHandler(RadioButtonChecked);
            RbDouble.CheckedChanged += new EventHandler(RadioButtonChecked);

            CbbFunCode.DataBindings.Add(new Binding("Text", _modCmd, "FunCode"));

            _modCmd.DataType = RbHex.Text;
        }
        /// <summary>
        /// 单选按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="eventArgs"></param>
        void RadioButtonChecked(object sender, EventArgs eventArgs)
        {
            var rb = sender as RadioButton;
            if (rb == null || !rb.Checked) return;
            _modCmd.DataType = rb.Text;
        }
        /// <summary>
        /// 发送区绑定
        /// </summary>
        void SendBinding()
        {
            //ChkAuto.DataBindings.Add(new Binding("Checked", _sendView, "IsAuto"));
            //ChkSendHex.DataBindings.Add(new Binding("Checked", _sendView, "IsHexShow"));
            //ChkNewLine.DataBindings.Add(new Binding("Checked", _sendView, "IsNewLine"));
            TxtInterv.DataBindings.Add(new Binding("Text", _sendView, "Interval"));
            TxtSend.DataBindings.Add(new Binding("Text", _sendView, "SendData"));

            _sendView.OnSendComplete += SendComplete;
        }
        #endregion


        #region

        public void SendComplete(bool sendSuccess, int sendLen)
        {
            _counter.AddSend(sendLen);
            TxtSendCount.Invoke(new Action(() =>
            {
                TxtSendCount.Text = _counter.SendCount;
            }));
        }
        private void OnRecevied(string data, int len)
        {
            _recView.Receive(data);
            TxtRec.Invoke(new Action(() => { TxtRec.Text = _recView.RecData; }));

            _counter.AddRec(len);
            TxtSendCount.Invoke(new Action(() =>
            {
                TxtRecCount.Text = _counter.RecCount;
            }));

            if (string.IsNullOrWhiteSpace(_fileName)) return;
            File.AppendAllText(_fileName,data);
        }

        #endregion

        void SendThreadRun()
        {
            if (ChkAuto.Checked)
            {
                while (_canSend)
                {
                    Application.DoEvents();
                    _sendView.Send();
                    Thread.Sleep(TimeSpan.FromMilliseconds(_sendView.Interval.ToInt32()));
                }
            }
            else
            {
                _sendView.Send();
            }
        }
    }
}
